﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using ReadR41;
using Dimeng.ArdisPostProcessor.HomagLC4.Ardis;
using Dimeng.ArdisPostProcessor.HomagLC4Adsn;

namespace Dimeng.ArdisPostProcessor.HomagLC4
{
    public class LC4Writer
    {
        private byte[] buffer = new byte[0x10];
        private Encoding encoding = new UTF8Encoding(false, true);
        private byte[] largeBuffer = new byte[0x800];
        private Stream writeStream;
        private Ardis.R41Data Data;

        public LC4Writer(Stream writestream, Ardis.R41Data data)
        {
            Data = data;
            writeStream = writestream;
        }

        public void Write()
        {
            this.Write(true);
            this.Write((ushort)9);//原来是10，目测低版本是9，高版本是10
            this.Write(Data.R41Name.Split('.')[0]);
            this.Write("优化日期");
            this.WriteParts(Data.Parts);
            this.WriteSheets(Data.Sheets);
            this.WriteNOList();//RestePlatten
            this.WritePatterns(Data.Patterns);
            this.Write("dimeng");//TitelTeileListe
            this.Write("dimeng");//TitelPlattenListe
            this.WriteNOList();//Katen
            this.WriteOrigin(LaufOrigin.AutoOnlineConvert);
            this.Write(false);//laufNichtLoeschen
            this.Write("dimeng");//NameTeileDaten
            this.Write("dimeng");//NamePlattenDatei
            this.Write("HDL_HPP180");//NameOptParaDatei
            this.Write("HDL_HPP180");//NameSawParaDatei
            this.WriteNOList();//STP2Liste
            this.WriteMaterials(Data.Materials);
            this.Write(false);//ProductionIsDone
            //老板本是没有的（num<=9)
            //this.WriteNOList();//AbstapelDaten
        }

        private void WriteNOList()
        {
            this.Write(true);

            this.Write((ushort)1);
            this.Write(0);
        }

        private void WriteOrigin(LaufOrigin laufOrigin)
        {
            this.Write(BinSerType.e_LaufOrigin);
            int a = (int)laufOrigin;
            this.Write(a);
        }

        private void WriteMaterials(List<Material> materails)
        {
            var UsedMaterials = materails.Where(it => Data.Sheets.Find(s => s.SheetMatNo == it.MaterialNo) != null).ToList();
            this.Write(true);

            this.Write((ushort)1);
            this.Write(UsedMaterials.Count);
            foreach (var m in UsedMaterials)
            {
                this.Write(m);
            }
        }

        private void Write(Material m)
        {
            this.Write(true);

            this.Write((ushort)1);
            this.WriteMaterialData(m);
        }

        private void WriteMaterialData(Material m)
        {
            this.Write((ushort)1);
            this.Write(m.MaterialName);
            this.Write(string.Empty);

            Sheet s = Data.Sheets.Find(it => it.SheetMatNo == m.MaterialNo);
            this.WriteHOmmValue(s.SheetThick);

            this.Write(false);//grain
        }

        private void WritePatterns(List<Pattern> patterns)
        {
            this.Write(true);

            this.Write((ushort)1);
            this.Write(patterns.Count);
            foreach (Pattern pattern in patterns)
            {
                this.WritePattern(pattern);
            }
        }

        private void WritePattern(Pattern pattern)
        {
            #region 计算各种面积数量
            double AbfallFlache = 0;//字面翻译是废物面积，但似乎不是这么算的
            double PlattenFlache = pattern.PatternL * pattern.PatternW;//大板面积
            double SchnittFlache = 0;//切割损耗面积
            double TeileFlache = 0;//板件的面积
            double Verschnitt = 0;//废物率
            int TeileAnzahl = 0;//板件数量
            var PatternCuts = Data.FullCuts.Where(it => it.CutPatternNo == pattern.PatternNumber).ToList();
            foreach (var cut in PatternCuts)
            {
                if (cut.CutPartNo > 0)
                {
                    Part part = Data.Parts.Find(it => it.PartNo == cut.CutPartNo);
                    TeileAnzahl += 1;
                    TeileFlache += part.PartL * part.PartW;
                }
                else
                {
                    if (cut.CutType == CutType.SawCut)
                    {
                        var parentCut = PatternCuts.Find(it => it.CutNo == cut.CutParentNo);
                        if (parentCut != null)
                        {
                            SchnittFlache += cut.CutW * parentCut.CutW;
                        }
                    }
                }
            }
            Verschnitt = 100 - TeileFlache / PlattenFlache * 100;
            #endregion

            Cut firstCut = Data.Cuts.Find(it => it.CutPatternNo == pattern.PatternNumber);
            double length;
            double width;
            if (firstCut.CutD == 'V')
            {
                length = pattern.PatternL;
                width = pattern.PatternW;
            }
            else
            {
                length = pattern.PatternW;
                width = pattern.PatternL;
            }

            this.Write(true);

            this.Write((ushort)4);
            this.WritePatternData(pattern, width);

            this.WriteHOmmValue(length);//长边进就是2440，转过来就是1220

            this.Write(pattern.PatternQty);//ProdSollTotal

            if (pattern.PatternQty <= pattern.MaxSheetsPerBook)//packageNumber
            {
                this.Write(pattern.PatternQty);
            }
            else this.Write(pattern.MaxSheetsPerBook);

            this.Write(pattern.PatternMaterial);
            this.WriteUnit();
            this.Write(false);//NurVonVorneAbarbeiten
            this.WritePatternParameterList(pattern);//TODO:未完成参数部分
            this.Write(pattern.PatternQty);
            this.Write(true);//Optimiert

            this.Write(AbfallFlache);//AbfallFlaeche
            this.Write(PlattenFlache);//PlattenFlaeche
            this.Write(0);//ResteAnzahl;
            this.Write((double)0);//ResteFlaeche
            this.Write(SchnittFlache);//SchnittFaeche
            this.Write(TeileAnzahl);//TeileAnzahl
            this.Write(TeileFlache);//TeileFlaeche
            this.Write(Verschnitt);//Verschnitt
            this.WritePlanType();
            //this.Write(0);//OptiSchnitteAnzahl
            //this.Write(0);//OptiZyklusZeitInSekunden
            //this.Write(0);//OptiGeasamtZeitInSekunden
            //this.Write(0);//Cad4ZyklusZeitInSekunden
            // this.Write(Data.FullCuts.Count(it => it.CutType == CutType.SawCut && it.CutPatternNo == pattern.PatternNumber));//Cad4SchnitteAnzahl
            // this.WriteHOmmValue(0);//Cad4schnitteLaenge

        }

        private void WritePatternData(Pattern pattern, double width)
        {
            this.Write((ushort)3);//原来是5，老板本是3
            this.Write(string.Format("{0:00000}", pattern.PatternNumber));
            this.Write(pattern.PatternMaterial);
            this.WriteHOmmValue(width);
            this.Write(1);//NumberOfCopies / AnzahlKopien
            this.WriteStreifenTyp(StreinType.Platte);
            this.WriteStreifenMassTyp(StreifenMassType.Fest);

            #region LagenListe
            //WriteLagenListe
            this.Write((ushort)1);
            this.Write(1);
            //WriteLage
            this.Write(true);
            this.Write((ushort)2);
            this.Write(pattern.PatternQty);//Qty
            #endregion
            //IsRotated
            if (width == pattern.PatternL)
                this.Write(true);
            else
                this.Write(false);

            this.Write("");//Qualitaet
            this.Write(false);//IsFinishePart
            this.Write(true);//BasisTeil!=null
            this.WriteLagenRefList(LagenRefList.e_refPlatternListe);

            this.Write(pattern.PatternSheetNumber - 1);//RefIndex，TODO:可能和Sheet是挂钩的

            //CutInfoList,TODO:把这部分先跳过了 - 事实上也不需要什么
            this.WriteNOList();

            #region ChildStreifen
            //StreifenListe
            this.Write(true);
            //StreifenListe.WriteObject
            this.Write((ushort)1);

            #region 做一个虚拟cut，作为pattern的第一个strip提供数据
            ExternCut VirtualCut = new ExternCut();
            VirtualCut.CutPatternNo = pattern.PatternNumber;
            VirtualCut.CutLevel = 0;
            VirtualCut.CutPartNo = 0;
            VirtualCut.CutQty = 1;
            VirtualCut.CutType = CutType.Strip;
            VirtualCut.CutW = (width == pattern.PatternL) ? pattern.PatternW : pattern.PatternL;
            #endregion
            this.Write(1);//虚拟刀的数量只有1个
            this.WriteStreifenData(VirtualCut);
            #endregion
            this.Write(false);//IstKopie
            this.WriteUserSeparation(SeperateType.Undef_Seperated);//UserSeparation

            //老板本没有下面这两个
            //this.Write(0);//AbstapeldatenID
            //this.Write(false);//UserSammeln
        }

        private void WriteStreifenData(ExternCut cut)
        {
            this.Write(true);

            var ChildCuts = Data
                            .FullCuts
                            .Where(it => it.CutPatternNo == cut.CutPatternNo
                                && it.CutParentNo == cut.CutNo
                                && it.CutLevel > cut.CutLevel);//找子Cut
            string name = string.Empty;
            string comment = string.Empty;
            double cutwidth = cut.CutW;
            StreinType Typ = StreinType.Anschnitt;
            StreifenMassType MassTyp = StreifenMassType.Undefined;

            Part part = null;

            if (cut.CutPartNo > 0)
            {
                part = Data.Parts.Find(it => it.PartNo == cut.CutPartNo);
            }

            if (part != null)
            {
                name = part.PartRef;
                comment = part.PartNo.ToString();
                cutwidth = cut.CutW;
                Typ = StreinType.Teil;
                MassTyp = StreifenMassType.Fest;
            }
            else if (cut.CutType == CutType.Strip)
            {
                name = "Streifen";
                MassTyp = StreifenMassType.Fest;
                Typ = StreinType.Strifen;
            }
            else if (cut.CutType == CutType.SawCut)
            {
                name = "Schnitt";
                MassTyp = StreifenMassType.Automatisch;
                Typ = StreinType.Schnitt;
            }
            else if (cut.CutType == CutType.Trim || cut.CutType == CutType.Rest)
            {
                name = "Anschnitt";
                MassTyp = StreifenMassType.Automatisch;
                Typ = StreinType.Anschnitt;
            }

            //Strip
            if (ChildCuts.Count() > 0)
            {
                name = "Streifen";
                if (ChildCuts.Count(it => it.CutPartNo > 0) == 0)
                {
                    Typ = StreinType.Strifen;
                    MassTyp = StreifenMassType.Flexibel;  //2013/09/03修改
                    //MassTyp = StreifenMassType.Fest;
                }
                else
                {
                    Typ = StreinType.Strifen;
                    //MassTyp = StreifenMassType.Flexibel;  //2013/09/03修改
                    MassTyp = StreifenMassType.Fest;
                }
            }

            this.Write((ushort)3);//由5改成了3，这个是基于样本设定的
            this.Write(name);
            this.Write(comment);
            this.WriteHOmmValue(cutwidth);
            this.Write(1);//NumberOfCopies
            this.WriteStreifenTyp(Typ);
            this.WriteStreifenMassTyp(MassTyp);

            this.WriteLagenListe(cut);

            this.WriteNOList();//Cutinfolist = null

            //TODO:Strips.Parent
            ////Aufteilung
            //if (ChildCuts.Count() == 0)
            //    this.Write(false);
            //else
            //{
            this.Write(true);

            this.Write((ushort)1);
            this.Write(ChildCuts.Count());

            //出现死循环？
            foreach (ExternCut childcut in ChildCuts)
            {
                WriteStreifenData(childcut);
            }
            //}

            this.Write(false);//IsKopie
            this.WriteUserSeparation(SeperateType.Undef_Seperated);

            //以下两个在老板本中不适用
            //this.Write(0);//AbstapeldatenID
            //this.Write(false);//UserSammeln
        }

        private void WriteLagenListe(ExternCut cut)
        {
            this.Write((ushort)1);

            var pat = Data.Patterns.Find(it => it.PatternNumber == cut.CutPatternNo);


            if (cut.CutPartNo > 0)
            {
                this.Write(pat.PatternQty);
                for (int i = 0; i < pat.PatternQty; i++)
                {
                    this.Write(true);

                    var part = FindPart(cut.CutPartNo);
                    this.WriteLage(cut, part);
                }
            }
            else
            {
                this.Write((int)0);
            }
            //foreach (Part p in cut.Parts)
            //{
            //    this.Write(true);
            //    this.WriteLage(cut, p);
            //}

        }

        private Part FindPart(int pid)
        {
            var part = Data.Parts.Find(it => it.PartNo == pid);
            if (part.PartQtyDone > 0)
            {
                part.PartQtyDone = part.PartQtyDone - 1;
                return part;
            }
            else
            {
                var p = Data.Parts.Find(it => it.PartL == part.PartL
                                           && it.PartW == part.PartW
                                           && it.PartMatNo == part.PartMatNo
                                           //&& it.PartD == part.PartD
                                           && it.PartQtyDone > 0);

                if (p == null)
                {
                    throw new Exception("未找到合适的板件");
                }
                p.PartQtyDone = p.PartQtyDone - 1;

                return p;
            }
        }

        private void WriteLage(ExternCut cut, Part p)
        {
            this.Write((ushort)2);
            this.Write((int)1); //板件数量，原来是引用PartQty，现在统一变为1，不接受复数个板件，全部拆成单一板件

            //判断是否旋转：
            //1、如果是竖切，判断切宽是否和板件长度相等
            //2、如果是横切，判断切宽是否和板件宽度相等
            if (cut.CutD == 'H')
            {
                if (p.PartL == cut.CutW)
                    this.Write(false);
                else this.Write(true);
            }
            else
            {
                if (p.PartW == cut.CutW)
                    this.Write(true);
                else this.Write(false);
            }

            this.Write(string.Empty);//Qualitaet
            this.Write(false);//IsFinishPart

            //BasisTeil
            this.Write(true);
            this.WriteLagenRefList(LagenRefList.e_refTeileListe);
            this.Write(p.PartNo - 1);
        }

        private void WriteLagenRefList(LagenRefList lagenRefList)
        {
            this.Write(BinSerType.e_LagenRefList);
            int o = (int)lagenRefList;
            this.Write(o);
        }

        private void WriteUserSeparation(SeperateType typ)
        {
            this.Write(BinSerType.e_SeparateTyp);
            int o = (int)typ;
            this.Write(o);
        }

        private void WriteStreifenMassTyp(StreifenMassType streifenMassType)
        {
            this.Write(BinSerType.e_StreifenMassType);
            int o = (int)streifenMassType;
            this.Write(o);
        }

        private void WriteStreifenTyp(StreinType streinType)
        {
            this.Write(BinSerType.e_StreifenTyp);
            int o = (int)streinType;
            this.Write(o);
        }

        private void WritePlanType()
        {
            this.Write(BinSerType.e_PlanType);
            this.Write(1);//Opti_PT
        }
        private void Write(double d)
        {
            this.Write(BinSerType.Double);
            byte[] bytes = BitConverter.GetBytes(d);
            this.writeStream.Write(bytes, 0, bytes.Length);
        }
        private void WritePatternParameterList(Pattern pattern)
        {
            this.Write(true);

            //ParameterList.WriteObject
            this.Write((ushort)1);

            if (false) //(Properties.Settings.Default.IsFloatTrimCut)
            {
                this.Write(7);//写58个参数

                this.WriteParameter("AnschnittLinks", pattern.PatternLeftTrim.ToString());
                this.WriteParameter("AnschnittMinimal", "0");
                this.WriteParameter("AnschnittNachschnittVorne", "0");//Properties.Settings.Default.FloatTrimCutValue.ToString());//recut front
                this.WriteParameter("AnschnittNullVorneNichtSchneiden", "False");
                this.WriteParameter("AnschnittOben", pattern.PatternTopTrim.ToString());
                this.WriteParameter("AnschnittRechts", pattern.PatternRightTrim.ToString());
                this.WriteParameter("AnschnittUnten", pattern.PatternBottomTrim.ToString());
            }
            else
            {
                this.Write(11);//写58个参数

                this.WriteParameter("AnschnittHintenOptimal", "50", false);
                this.WriteParameter("AnschnittKopf", "0");
                this.WriteParameter("AnschnittLinks", pattern.PatternLeftTrim.ToString());
                this.WriteParameter("AnschnittMinimal", "0");
                this.WriteParameter("AnschnittMinimalUnterschreitungErlaubt", "True");
                this.WriteParameter("AnschnittNachschnittHinten", "0");
                this.WriteParameter("AnschnittNachschnittVorne", "0");//recut front
                this.WriteParameter("AnschnittNullVorneNichtSchneiden", "False");//第一刀=0时切割不为XXX
                this.WriteParameter("AnschnittOben", pattern.PatternTopTrim.ToString());
                this.WriteParameter("AnschnittRechts", pattern.PatternRightTrim.ToString());
                this.WriteParameter("AnschnittUnten", pattern.PatternBottomTrim.ToString());
            }


            //this.WriteParameter("AbfallKleinSchneideMass_QS", "0");
            //this.WriteParameter("AbfallKleinSchneidenAbLaenge", "9999.9", false);
            //this.WriteParameter("AbfallPos_QS", "0");
            //this.WriteParameter("AbhandlungQuerschnittplaeneVonHinten", "0", false);
            //this.WriteParameter("Absaugung_Zu_AbMass_QS", "10", false);
            //this.WriteParameter("Absaugung_Zu_BisMass_QS", "1", false);

            ////this.WriteParameter("AnschnittHintenOptimal", "50", false);
            ////this.WriteParameter("AnschnittKopf", "0");
            //this.WriteParameter("AnschnittLinks", pattern.PatternLeftTrim.ToString());
            //this.WriteParameter("AnschnittMinimal", "0");
            ////this.WriteParameter("AnschnittMinimalUnterschreitungErlaubt", "True");
            ////this.WriteParameter("AnschnittNachschnittHinten", "0");
            //this.WriteParameter("AnschnittNachschnittVorne", pattern.PatternLeftTrim.ToString());//recut front
            //this.WriteParameter("AnschnittNullVorneNichtSchneiden", "False");
            //this.WriteParameter("AnschnittOben", pattern.PatternTopTrim.ToString());
            //this.WriteParameter("AnschnittRechts", pattern.PatternRightTrim.ToString());
            //this.WriteParameter("AnschnittUnten", pattern.PatternBottomTrim.ToString());

            //this.WriteParameter("AusschieberAktivAbLaengsschnittMass", "4000", false);
            //this.WriteParameter("AusschieberAktivAbQuerschnittMass", "2000", false);
            //this.WriteParameter("AusschnittBezug", "0", false);
            //this.WriteParameter("AusschnittBezugEcke", "0", false);
            //this.WriteParameter("AusschnittBreite", "100", false);
            //this.WriteParameter("AusschnittEckSteg", "0", false);
            //this.WriteParameter("AusschnittEcke", "0", false);
            //this.WriteParameter("AusschnittLaenge", "100", false);
            //this.WriteParameter("AusschnittPosX", "0", false);
            //this.WriteParameter("AusschnittPosY", "0", false);
            //this.WriteParameter("DB_Anpressdruck", "4", false);
            //this.WriteParameter("EinschubHoeheMaximal", "54");
            //this.WriteParameter("HauptsaegeDrehzahl", "3800", false);
            //this.WriteParameter("KoepfeNachHauptteil", "False", false);
            //this.WriteParameter("MassEinheit", "0");
            //this.WriteParameter("MassHauptplatteSymmetrischMaximal", "1300", false);
            //this.WriteParameter("MinMassVorletzterSchnitt_QS", "50", false);
            //this.WriteParameter("NachschnittGegenFixPos", "False");
            //this.WriteParameter("NachschnitteNachQuerschneiden", "True", false);
            //this.WriteParameter("NachschnitteZuschneiden", "True");
            //this.WriteParameter("NutBreite", "4.8", false);
            //this.WriteParameter("NutLage", "0", false);
            //this.WriteParameter("NutPos", "100", false);
            //this.WriteParameter("NutZustellMass", "4.8", false);
            //this.WriteParameter("OptiIgnoreResteAbfallPara", "False");
            //this.WriteParameter("OptiKopfNachoptimieren", "False", false);
            //this.WriteParameter("OptiNut180GradDrehen", "True");
            //this.WriteParameter("OptiReihenfolgeDrehen", "False");
            //this.WriteParameter("OptiRestePos", "0");
            //this.WriteParameter("Opti_NachschnittKanteEliminieren", "False", false);
            //this.WriteParameter("Paket", "1", false);/////////
            //this.WriteParameter("PaketHoeheMaximal", "80");
            //this.WriteParameter("PaketVermitteln", "False", false);
            //this.WriteParameter("PlattenBreite", "2070", false);
            //this.WriteParameter("PlattenLaenge", "2750", false);
            //this.WriteParameter("PlattenDicke", "16", false);
            //this.WriteParameter("Plattenmaserung", "False");
            //this.WriteParameter("ResteBreite", "60");
            //this.WriteParameter("ResteFlaeche", "0.01");
            //this.WriteParameter("ResteLaenge", "450");
            //this.WriteParameter("ResteVorne", "True");
            //this.WriteParameter("SaegeblattDurchmesser", "450", false);
            //this.WriteParameter("SaegeblattStaerke", "4.1", false);
            //this.WriteParameter("SaegeblattStaerke_QS", "4.8", false);
            //this.WriteParameter("SaegeblattUeberstand", "125", false);
            //this.WriteParameter("SB_Ueberstand_QS", "20", false);
            //this.WriteParameter("SchnittReihenfolgeDrehenAbLaenge", "9999", false);
            //this.WriteParameter("SFS1Breite", "10", false);
            //this.WriteParameter("SlowDownGeschwindigkeit", "10", false);
            //this.WriteParameter("SlowDownStartPunkt", "250", false);
            //this.WriteParameter("StreifenZusammenfassenDefault", "0", false);
            //this.WriteParameter("SW_GeschwindigkeitBeiKleinerPakethoehe", "80", false);
            //this.WriteParameter("SW_GeschwindigkeitBeiVollerPakethoehe", "30", false);
            //this.WriteParameter("SW_GeschwindigkeitKratzschnittBeiKleinerPakethoehe", "50", false);
            //this.WriteParameter("SW_GeschwindigkeitKratzschnittBeiVollerPakethoehe", "15", false);
            //this.WriteParameter("SW_GeschwindigkeitSteuerungUeberKratzschnitt", "1", false);
            //this.WriteParameter("SW_GeschwindigkeitSteuerungUeberPakethoehe", "1", false);
            //this.WriteParameter("SW_KratzschnittMass", "20", false);
            //this.WriteParameter("Total", "1", false);
            //this.WriteParameter("VerpackungsstreifenAbLange_KS", "592", false);
            //this.WriteParameter("VerpackungsstreifenAbLange_LS", "592", false);
            //this.WriteParameter("VerpackungsstreifenAbLange_QS", "592", false);
            //this.WriteParameter("VerpackungsstreifenBreite_QS", "0", false);
            //this.WriteParameter("WA_AusrichtOffset", "-5.0", false);
        }

        private void WriteUnit()
        {
            this.Write((ushort)1);
            this.Write(BinSerType.e_HOUnit);
            this.Write(2);//int=2,代表Length_mm
        }

        private void WriteSheets(List<Sheet> list)
        {
            this.Write(true);

            this.Write((ushort)1);
            this.Write(list.Count);
            foreach (Sheet sheet in list)
            {
                WriteSheets(sheet);
            }
        }

        private void WriteSheets(Sheet sheet)
        {
            this.Write(true);
            this.Write((ushort)1);

            //WriteBasisTeilData
            this.Write((ushort)2);
            this.Write(sheet.SheetNo.ToString());
            this.Write(sheet.SheetNo.ToString());
            this.Write(Data.Materials.Find(it => it.MaterialNo == sheet.SheetMatNo).MaterialName);
            this.WriteHOmmValue(sheet.SheetL);
            this.WriteHOmmValue(sheet.SheetW);
            this.WriteHOmmValue(sheet.SheetThick);
            this.Write(99999);
            this.Write(sheet.SheetUsed + 1);
            this.WriteGrain(0);//当成都是无纹理
            this.Write(false);

            #region Sheet的ParameterList
            this.Write(true);

            //ParameterList.WriteObject
            this.Write((ushort)1);
            this.Write((int)0);//参数数量
            #endregion

            this.Write(true);
        }

        private void WriteParts(List<ReadR41.Part> list)
        {
            if (list == null)
                this.Write(false);
            else
            {
                this.Write(true);

                //TeilListe.WriteObject
                this.Write((ushort)1);
                this.Write(list.Count);
                foreach (Part p in list)
                {
                    this.Write(p);
                }
            }
        }

        private void Write(Part p)
        {
            this.Write(true);

            this.Write((ushort)1);

            //WriteBasisTeilData
            this.Write((ushort)2);
            this.Write(p.PartRef);
            this.Write(p.PartNo.ToString());
            this.Write(Data.Materials.Find(it => it.MaterialNo == p.PartMatNo).MaterialName);
            this.WriteHOmmValue(p.PartL);
            this.WriteHOmmValue(p.PartW);

            var sheet = Data.Sheets.Find(it => it.SheetMatNo == p.PartMatNo);
            if(sheet==null)
            {
                throw new Exception("unknown sheet!");
            }

            this.WriteHOmmValue(sheet.SheetThick);
            this.Write(p.PartQty);
            this.Write(p.PartQty);
            this.WriteGrain(p.PartD);
            this.Write(false);//IsSchonplatte
            this.WritePartParameterList(p);
            this.Write(true);//InVerwendung

        }

        private void WritePartParameterList(Part p)
        {
            this.Write(true);

            //ParameterList.WriteObject
            this.Write((ushort)1);

            //this.Write(0);//先写个0吧，TODO:下面的内容再说
            this.Write(30);//参数数量

            this.WriteParameter("AddInfo_001", ExpressionDictionary.GetPartValueByKey("AddInfo1", p));
            this.WriteParameter("AddInfo_002", ExpressionDictionary.GetPartValueByKey("AddInfo2", p));
            this.WriteParameter("AddInfo_003", ExpressionDictionary.GetPartValueByKey("AddInfo3", p));
            this.WriteParameter("AddInfo_004", ExpressionDictionary.GetPartValueByKey("AddInfo4", p));
            this.WriteParameter("AddInfo_005", ExpressionDictionary.GetPartValueByKey("AddInfo5", p));
            this.WriteParameter("AddInfo_006", ExpressionDictionary.GetPartValueByKey("AddInfo6", p));
            this.WriteParameter("AddInfo_007", ExpressionDictionary.GetPartValueByKey("AddInfo7", p));
            this.WriteParameter("AddInfo_008", ExpressionDictionary.GetPartValueByKey("AddInfo8", p));
            this.WriteParameter("AddInfo_009", ExpressionDictionary.GetPartValueByKey("AddInfo9", p));
            this.WriteParameter("AddInfo_010", ExpressionDictionary.GetPartValueByKey("AddInfo10", p));
            this.WriteParameter("AddInfo_011", ExpressionDictionary.GetPartValueByKey("AddInfo11", p));
            this.WriteParameter("AddInfo_012", ExpressionDictionary.GetPartValueByKey("AddInfo12", p));
            this.WriteParameter("AddInfo_013", ExpressionDictionary.GetPartValueByKey("AddInfo13", p));
            this.WriteParameter("AddInfo_014", ExpressionDictionary.GetPartValueByKey("AddInfo14", p));
            this.WriteParameter("AddInfo_015", ExpressionDictionary.GetPartValueByKey("AddInfo15", p));
            this.WriteParameter("AddInfo_016", ExpressionDictionary.GetPartValueByKey("AddInfo16", p));
            this.WriteParameter("AddInfo_017", ExpressionDictionary.GetPartValueByKey("AddInfo17", p));
            this.WriteParameter("AddInfo_018", ExpressionDictionary.GetPartValueByKey("AddInfo18", p));
            this.WriteParameter("AddInfo_019", ExpressionDictionary.GetPartValueByKey("AddInfo19", p));
            this.WriteParameter("AddInfo_020", ExpressionDictionary.GetPartValueByKey("AddInfo20", p));
            this.WriteParameter("AddInfo_021", ExpressionDictionary.GetPartValueByKey("AddInfo21", p));
            this.WriteParameter("AddInfo_022", ExpressionDictionary.GetPartValueByKey("AddInfo22", p));
            this.WriteParameter("AddInfo_023", ExpressionDictionary.GetPartValueByKey("AddInfo23", p));
            this.WriteParameter("AddInfo_024", ExpressionDictionary.GetPartValueByKey("AddInfo24", p));
            this.WriteParameter("AddInfo_025", ExpressionDictionary.GetPartValueByKey("AddInfo25", p));
            this.WriteParameter("AddInfo_026", ExpressionDictionary.GetPartValueByKey("AddInfo26", p));
            this.WriteParameter("AddInfo_027", ExpressionDictionary.GetPartValueByKey("AddInfo27", p));
            this.WriteParameter("AddInfo_028", ExpressionDictionary.GetPartValueByKey("AddInfo28", p));
            this.WriteParameter("AddInfo_029", ExpressionDictionary.GetPartValueByKey("AddInfo29", p));
            this.WriteParameter("AddInfo_030", ExpressionDictionary.GetPartValueByKey("AddInfo30", p));
        }
        private void WriteParameter(string name, string value)
        {
            this.WriteParameter(name, value, true);
        }
        private void WriteParameter(string name, string value, bool IsChanged)
        {
            this.Write(true);

            //Parameter.WriteObject
            this.Write((ushort)2);
            this.Write(name);
            this.Write(value);
            this.Write(IsChanged);//ValueChanged
        }
        private void WriteGrain(int p)
        {
            this.Write(BinSerType.e_Maserung);
            if (p == 0)
                this.Write(p);
            else if (p == 1)
                this.Write(2);
            else this.Write(3);
        }

        private void WriteHOmmValue(double value)
        {
            this.Write(BinSerType.HOmm);
            this.Write((ushort)1);
            long l = (long)(value * 100000);
            this.Write(l);
            this.Write(false);//homm.IsNaN
        }
        public void Write(long l)
        {
            this.Write(BinSerType.Long);
            byte[] bytes = BitConverter.GetBytes(l);
            this.writeStream.Write(bytes, 0, bytes.Length);
        }
        public void Write(ushort o)
        {
            Write(BinSerType.UShort);
            this.buffer[0] = (byte)o;
            this.buffer[1] = (byte)(o >> 8);
            this.writeStream.Write(this.buffer, 0, 2);
        }

        public void Write(BinSerType typ)
        {
            ushort num = (ushort)typ;
            this.buffer[0] = (byte)num;
            this.buffer[1] = (byte)(num >> 8);
            this.writeStream.Write(this.buffer, 0, 2);
        }

        public void Write(string o)
        {
            this.Write(BinSerType.String);
            if (o == null)
                this.Write(false);
            else
            {
                this.Write(true);
                this.Write(o.ToCharArray());
            }

        }

        private void Write(char[] p)
        {
            this.Write(BinSerType.Char_Array);



            int num = this.encoding.GetByteCount(p, 0, p.Length);
            this.Write(num);
            if (num != 0)
            {
                byte[] bytes = new byte[num];
                int num2 = this.encoding.GetBytes(p, 0, p.Length, bytes, 0);
                if (num != num2)
                {
                    throw new Exception("Error");
                }
                this.writeStream.Write(bytes, 0, num);
            }
        }

        private void Write(int num)
        {
            this.Write(BinSerType.Int);
            this.buffer[0] = (byte)num;
            this.buffer[1] = (byte)(num >> 8);
            this.buffer[2] = (byte)(num >> 0x10);
            this.buffer[3] = (byte)(num >> 0x18);
            this.writeStream.Write(buffer, 0, 4);
        }

        private void Write(bool p)
        {
            this.Write(BinSerType.Boolean);
            if (!p)
            {
                this.buffer[0] = 0;
            }
            else
            {
                this.buffer[0] = 1;
            }
            this.writeStream.Write(this.buffer, 0, 1);
        }
    }
}
